package com.kairos.commands
{
	import com.bourre.commands.Command;
	import com.bourre.commands.MockCommand;
	import com.bourre.structures.Range;
	import com.kairos.engine.MockRTBeacon;
	import com.kairos.log.KairosDebug;
	
	import flash.display.MovieClip;
	
	import flexunit.framework.TestCase;
	import com.bourre.commands.MockASyncCommandListener;

	public class FrameControllerRTTest extends TestCase
	{
		[Embed(source="../motion/anim.swf",symbol="Animation")] 
			private var Animation : Class;
		
		private var _fcrt : MockFrameControllerRT;
		private var _oB : MockRTBeacon;
		private var _mc : MovieClip;
		private var _c : MockCommand;
		
		public override function setUp() : void
		{
			_mc = new Animation();
			_fcrt = new MockFrameControllerRT ( _mc );
			_c = new MockCommand();
			_oB = MockRTBeacon.getInstance();
			_oB.setStep( 25 );
		}
		
		public override function tearDown():void
		{
			_fcrt.stop();
		}
		public function testConstruct () : void 
		{
			assertNotNull ( "AdvancedMovieClipRT constructor returns null", _fcrt );
			assertNotNull ( _fcrt + ".getMovieClip() return null after creation", _fcrt.getMovieClip() );
			assertEquals ( _fcrt + ".getFramerate() don't return the default value", 40, _fcrt.getFramerate() );
			assertNotNull ( _fcrt + ".getRange() return null", _fcrt.getRange() );
			assertEquals ( _fcrt + ".getLoopCount() don't return 0", 0, _fcrt.getLoopCount() );
		}
		public function testManageCommands () : void
		{
			assertTrue ( _fcrt + ".addCommand() failed to add the command at 1", _fcrt.addCommand( 1, _c ) );
			assertTrue ( _fcrt + ".addCommand() failed to add the same command at 2", _fcrt.addCommand( 2, _c ) );
			assertTrue ( _fcrt + ".addCommand() failed to add the same command at 3", _fcrt.addCommand( 3, _c ) );
			assertFalse ( _fcrt + ".addCommand() don't failed to add the same command at 3", _fcrt.addCommand( 3, _c ) );
			assertFalse ( _fcrt + ".addCommand() don't failed to add an invalid command at 4", _fcrt.addCommand( 4, null ) );
			assertFalse ( _fcrt + ".addCommand() don't failed to add a command at an invalid index", _fcrt.addCommand( 150, _c ) );
			
			assertTrue ( _fcrt + ".addProxy() failed to add the proxy at 4", _fcrt.addProxy( 4, proxyTest, "foo" ) );
			assertFalse ( _fcrt + ".addProxy() don't failed to add an invalid proxy at 5", _fcrt.addProxy( 5, null ) );
			
			assertTrue ( _fcrt + ".addStop() failed to add a stop at 5", _fcrt.addStop( 5 ) );
			assertFalse ( _fcrt + ".addStop() don't failed to add a stop at an invalid index 150", _fcrt.addStop( 150 ) );
			
			assertEquals ( _fcrt + ".getCommand() failed to get the command at 1", _c, _fcrt.getCommand( 1 ) ); 
			assertEquals ( _fcrt + ".getCommand() failed to get the command at 2", _c, _fcrt.getCommand( 2 ) ); 
			assertEquals ( _fcrt + ".getCommand() failed to get the command at 3", _c, _fcrt.getCommand( 3 ) ); 
			
			assertTrue ( _fcrt + ".remove() failed to remove the command at 1", _fcrt.remove( _c ) );
			assertNull ( _fcrt + ".getCommand() continue to find the removed command at 1", _fcrt.getCommand( 1 ) ); 
			assertTrue ( _fcrt + ".remove() failed to remove the command a second time at 2", _fcrt.remove( _c ) );
			assertNull ( _fcrt + ".getCommand() continue to find the removed command at 2",_fcrt.getCommand( 2 ) ); 
			assertTrue ( _fcrt + ".removeAt() failed to remove the command at 3", _fcrt.removeAt( 3 ) );
			assertNull ( _fcrt + ".getCommand() continue to find the removed command at 3", _fcrt.getCommand( 3 ) ); 
		}
		
		public function proxyTest ( s : String, ... rest ) : void
		{
			assertNotNull ( "proxyTest argument is null", s );
		} 
		public function proxyTestFailure ( s : String, ... rest ) : void
		{
			throw new Error ( "proxyTestFailure have been called" );
		}
		
		public function testRunCommands () : void 
		{
			//KairosDebug.DEBUG( "RUNNING COMMANDS ----------------------------------------" );
			
			var n : Number = 0;
			
			_fcrt.addCommand( 10, _c );
			_fcrt.addProxy( 11, proxyTest, "hello" );
			_fcrt.addStop( 12 );
			_fcrt.addProxy( 13, proxyTestFailure, "hello" );
			
			_fcrt.setLoopCount( 1 );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 11, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 12, _mc.currentFrame );
			
			assertTrue( _fcrt + " haven't called the command at 11", _c.called );
			assertEquals( _fcrt + " haven't called the command only one time", 1, _c.callCount );
		}
		
		public function testRunCommandsWithBigStep () : void 
		{
			//KairosDebug.DEBUG( "RUNNING COMMANDS ----------------------------------------" );
			
			var n : Number = 0;
			
			_oB.setStep( 100 );
			
			_fcrt.addCommand( 10, _c );
			_fcrt.addProxy( 11, proxyTest, "hello" );
			_fcrt.addStop( 12 );
			_fcrt.addProxy( 13, proxyTestFailure, "hello" );
			
			_fcrt.setLoopCount( 1 );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 3, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 12, _mc.currentFrame );
			
			assertTrue( _fcrt + " haven't called the command at 11", _c.called );
			assertEquals( _fcrt + " haven't called the command only one time", 1, _c.callCount );
		}
		public function testRunLoopCommands () : void
		{
			//KairosDebug.DEBUG( "RUNNING LOOP COMMANDS ----------------------------------------" );
			
			var n : Number = 0;
			
			_fcrt.addCommand( 10, _c );
			_fcrt.addProxy( 11, proxyTest, "hello" );
		
			_fcrt.setLoopCount( 4 );		
			_fcrt.start();	
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 79, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 20, _mc.currentFrame );
			
			assertTrue( _fcrt + " haven't called the command at 11", _c.called );
			assertEquals( _fcrt + " haven't called the command 4 time", 4, _c.callCount );
		}
		public function testRunLoopCommandsWithBigStep () : void
		{
			//KairosDebug.DEBUG( "RUNNING LOOP COMMANDS BIG STEP ----------------------------------------" );
			
			var n : Number = 0;
			
			_fcrt.addCommand( 10, _c );
			_fcrt.addProxy( 11, proxyTest, "hello" );
			
			_oB.setStep( 100 );
		
			_fcrt.setLoopCount( 4 );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 20, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 20, _mc.currentFrame );
			
			assertTrue( _fcrt + " haven't called the command at 11", _c.called );
			assertEquals( _fcrt + " haven't called the command 4 time", 4, _c.callCount );
			
		}
		public function testRun () : void 
		{
			//KairosDebug.DEBUG( "RUNNING ----------------------------------------" );
			
			var n : Number = 0;
			
			_fcrt.setLoopCount( 1 );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 19, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 20, _mc.currentFrame );
			
		}
		public function testRunWithLocalSpeed () : void 
		{
			//KairosDebug.DEBUG( "RUNNING ----------------------------------------" );
			
			var n : Number = 0;
			_fcrt.setLocalSpeed( 2 );
			_fcrt.setLoopCount( 1 );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 10, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 20, _mc.currentFrame );
			
		}
		public function testRunBigStep () : void 
		{
			//KairosDebug.DEBUG( "RUNNING BIG STEP ----------------------------------------" );
			
			var n : Number = 0;
			
			_oB.setStep( 100 );
			_fcrt.setLoopCount( 1 );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 5, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 20, _mc.currentFrame );
			
		}
		public function testRunLoop () : void
		{
			//KairosDebug.DEBUG( "RUNNING LOOP ----------------------------------------" );
			
			var n : Number = 0;	
			
			_fcrt.setLoopCount( 4 );		
			_fcrt.start();	
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 79, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 20, _mc.currentFrame );
		}
		
		public function testRunLoopWithBigStep():void
		{
			//KairosDebug.DEBUG( "RUNNNING LOOP WITH BIG STEP ----------------------------------------" );
			
			var n : Number = 0;
			_oB.setStep( 100 );
			_fcrt.setLoopCount( 4 );				
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 20, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 20, _mc.currentFrame );
			
		}
		
		public function testRunReversed () : void 
		{
			//KairosDebug.DEBUG( "REVERSED ----------------------------------------" );
			
			var n : Number = 0;
			
			_fcrt.reverse();
			_fcrt.reset();
			_fcrt.setLoopCount( 1 );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() (reversed) haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation (reversed) in the time", 19, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 1, _mc.currentFrame );
		}
		public function testRunReversedWithBigStep () : void 
		{
			//KairosDebug.DEBUG( "REVERSED BIG STEP ----------------------------------------" );
			
			var n : Number = 0;
			
			_oB.setStep( 100 );
			
			_fcrt.reverse();
			_fcrt.reset();
			_fcrt.setLoopCount( 1 );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() (reversed) haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation (reversed) in the time", 5, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 1, _mc.currentFrame );
		}
		public function testReversedLoop () :void
		{
			//KairosDebug.DEBUG( "REVERSED LOOP ----------------------------------------" );
			
			var n : Number = 0;
			_fcrt.reverse();		
			_fcrt.setLoopCount( 4 );
			_fcrt.reset();	
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() (reversed) haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation (reversed) in the time", 79, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 1, _mc.currentFrame );
		}
		public function testReversedLoopWithBigStep() : void
		{
			//KairosDebug.DEBUG( "REVERSED LOOP BIG STEP ----------------------------------------" );
			
			_oB.setStep( 100 );
			var n : Number = 0;	
			_fcrt.setLoopCount( 4 );
			_fcrt.reverse();		
			_fcrt.reset();
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() (reversed) haven't finish its run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation (reversed) in the time", 20, n );
			assertEquals ( _fcrt + " last frame isn't the attempted one", 1, _mc.currentFrame );
		}		
		public function testRunInRange () : void 
		{
			//KairosDebug.DEBUG( "RANGE ----------------------------------------" );
			
			var n : Number = 0;
			
			_fcrt.setLoopCount( 4 );
			_fcrt.setRange( new Range ( 11, 20 ) );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish is run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 39, n );	
		}
		public function testRunInMinimalRange () : void
		{
			//KairosDebug.DEBUG( "RANGE MINIMUM ----------------------------------------" );
			
			var n: Number = 0;
			
			_fcrt.setLoopCount( 4 );
			_fcrt.setRange( new Range ( 11, 12 ) );
			_fcrt.start();
			
			while( _fcrt.isRunning() && n < 20 ) 
			{
				_oB.onTick( null );
				n++;
			}
			
			assertFalse ( _fcrt + ".isRunning() haven't finish is run", _fcrt.isRunning() );	
			assertEquals ( _fcrt + " haven't realized the animation in the time", 7, n );	
		}
		
		public function testRunEndLess () : void 
		{
			//KairosDebug.DEBUG( " RUNNING ENDLESS ----------------------------------------" );
			
			var n : Number = 0;

			_fcrt.start();
			
			while( n < 500 ) 
			{
				_oB.onTick( null );
				n++;
			}
			assertTrue ( _fcrt + ".isRunning() have finish its run", _fcrt.isRunning() );		
		}
		
		public function testSetLoopCount () : void
		{
			_fcrt.setLoopCount ( 20 );
			
			assertEquals ( _fcrt + ".setLoopCount() failed to defines the new count", 20, _fcrt.getLoopCount() );
		}
		
		public function testSetRange () : void
		{
			_fcrt.setRange ();
			assertNotNull ( _fcrt + ".getRange() return null", _fcrt.getRange() );
			assertEquals ( _fcrt + ".getRange().min don't return 1", 1, _fcrt.getRange().min );
			assertEquals ( _fcrt + ".getRange().max don't return 20", 20, _fcrt.getRange().max );
			
			_fcrt.setRange ( new Range ( 2,8 ) );
			assertNotNull ( _fcrt + ".getRange() return null", _fcrt.getRange() );
			assertEquals ( _fcrt + ".getRange().min don't return 2", 2, _fcrt.getRange().min );
			assertEquals ( _fcrt + ".getRange().max don't return 8", 8, _fcrt.getRange().max );
			
			_fcrt.setRange ( new Range ( -2,58 ) );
			assertNotNull ( _fcrt + ".getRange() return null", _fcrt.getRange() );
			assertEquals ( _fcrt + ".getRange().min don't return 1", 1, _fcrt.getRange().min );
			assertEquals ( _fcrt + ".getRange().max don't return 20", 20, _fcrt.getRange().max );
			
			var errorOccurs : Boolean = false;
			try
			{
				_fcrt.setRange( new Range ( 11, 11 ) );
			}
			catch( e : Error )
			{
				errorOccurs = true;
			}
			assertTrue ( _fcrt + "don't failed when specifying a range of length 0" );
		}
		public function testReverse () : void 
		{
			var a : Array = [6, 2, 6, 2, 6];
			var n : Number = 0;
			
			_oB.setStep( 100 );
			
			_fcrt.setLooping( false );
			_fcrt.gotoAndStop( 2 );
			_fcrt.start();
			
			while( n <= 4 ) 
			{
				_oB.onTick( null );
				assertEquals ( _fcrt + ".reverse() failed to change the way of the animation", a[n], _mc.currentFrame );
				_fcrt.reverse();
				n++;
			}
		}
		
		public function testReset () : void 
		{
			var a : Array = [5, 5, 5, 5, 5];
			var n : Number = 0;
			
			_oB.setStep( 100 );
			
			_fcrt.setLooping( false );
			_fcrt.start();
			
			while( n <= 4 ) 
			{
				_oB.onTick( null );
				assertEquals ( _fcrt + ".reset() failed to place the frame to start", a[n], _mc.currentFrame );
				_fcrt.reset();
				n++;
			}
		}
		
		public function testShowHide () : void 
		{
			assertTrue( _mc + ".visible isn't true at creation", _mc.visible );
			
			_fcrt.hide();
			
			assertFalse( _mc + ".visible isn't false after a hide call", _mc.visible );
			
			_fcrt.show();
			
			assertTrue( _mc + ".visible isn't true after a show call", _mc.visible );
		}
		
		
		public function testAsyncBehavior () : void 
		{
			var m : MockASyncCommandListener = new MockASyncCommandListener();
			
			_fcrt.setLoopCount( 1 );
			_fcrt.addASyncCommandListener( m );
			_fcrt.start();
			
			while( _fcrt.isRunning() ) 
			{
				_oB.onTick( null );
			}
			assertTrue ( _fcrt + " haven't dispatch the onCommandEnd event", m.called );
		}
		/*
		public function testGotoAndPlay () : void 
		{
			_fcrt.gotoAndPlay( 10 );
			assertTrue ( _fcrt + ".isRunning() return false after a gotoAndPlay() call", _fcrt.isRunning() );
			assertEquals ( _fcrt + ".gotoAndPlay() failed to move the playhead", 10, _mc.currentFrame );
			
			_fcrt.gotoAndPlay( "lastLabel" );
			assertTrue ( _fcrt + ".isRunning() return false after a second gotoAndPlay() call", _fcrt.isRunning() );
			assertEquals ( _fcrt + ".gotoAndPlay() failed to move the playhead to the label", 20, _mc.currentFrame );
			
			_fcrt.stop();
			_fcrt.gotoAndPlay( true );
			assertFalse ( _fcrt + ".isRunning() return true after having pass an invalid label", _fcrt.isRunning() );
			assertEquals ( _fcrt + ".gotoAndPlay() move the playhead while passing an invalid label", 20, _mc.currentFrame );
		}
		
		public function testGotoAndStop () : void 
		{
			_fcrt.start()
			
			_fcrt.gotoAndStop( 10 );
			assertFalse ( _fcrt + ".isRunning() return true after a gotoAndStop() call", _fcrt.isRunning() );
			assertEquals ( _fcrt + ".gotoAndStop() failed to move the playhead", 10, _mc.currentFrame );
			
			_fcrt.gotoAndStop( "lastLabel" );
			assertFalse ( _fcrt + ".isRunning() return false after a second gotoAndStop() call", _fcrt.isRunning() );
			assertEquals ( _fcrt + ".gotoAndStop() failed to move the playhead to the label", 20, _mc.currentFrame );
			
			_fcrt.start();
			_fcrt.gotoAndStop( true );
			assertTrue ( _fcrt + ".isRunning() return true after having pass an invalid label", _fcrt.isRunning() );
			assertEquals ( _fcrt + ".gotoAndStop() move the playhead while passing an invalid label", 20, _mc.currentFrame );
		}		
		*/
		public function testLocalSpeedGetterSetter () : void 
		{
			var errorOccurs : Boolean;
			
			errorOccurs = false;
			try
			{
				_fcrt.setLocalSpeed( 0 );
			}
			catch ( e : Error )
			{
				errorOccurs = true;
			}
			
			assertTrue( _fcrt + ".setLocalSpeed() don't failed with a value of 0", errorOccurs );
			assertEquals ( _fcrt + ".setLocalSpeed() with an invalid argument have modify the local speed", 1, _fcrt.getLocalSpeed() );
			
			errorOccurs = false;
			try
			{
				_fcrt.setLocalSpeed( -1 );
			}
			catch ( e : Error )
			{
				errorOccurs = true;
			}
			
			assertTrue( _fcrt + ".setLocalSpeed() don't failed with a negative value", errorOccurs );
			assertEquals ( _fcrt + ".setLocalSpeed() with an invalid argument have modify the local speed", 1, _fcrt.getLocalSpeed() );
			
			
			_fcrt.setLocalSpeed( 2 );
			assertEquals ( _fcrt + ".setLocalSpeed() failed to change the local speed", 2, _fcrt.getLocalSpeed() );
			
		}
		public function testTickBeaconGetterSetter () : void 
		{
			var errorOccurs : Boolean;
			
			errorOccurs = false;
			try
			{
				_fcrt.setTickBeacon( null );
			}
			catch ( e : Error )
			{
				errorOccurs = true;
			}
			
			assertTrue( _fcrt + ".setTickBeacon() don't failed with a null beacon", errorOccurs );
			
			var beacon : MockRTBeacon = new MockRTBeacon ();
			
			_fcrt.setTickBeacon( beacon );
			
			assertEquals ( _fcrt + ".setTickBeacon() failed to set the new beacon", beacon, _fcrt.getTickBeacon() );
		}
		public function testStartStop() : void
		{
			_fcrt.start ();
			
			_oB.onTick( null );
			assertTrue( _fcrt + ".isRunning() return false after a call of start", _fcrt.isRunning() );
			
			_fcrt.stop ();
			
			assertFalse( _fcrt + ".isRunning() return true after a call of sop", _fcrt.isRunning() );
		}
		
		public function testStartAlias () : void
		{
			_fcrt.execute ();
			assertTrue( _fcrt + ".isRunning() return false after a call of execute", _fcrt.isRunning() );
			_fcrt.stop ();
			
			_fcrt.play ();
			assertTrue( _fcrt + ".isRunning() return false after a call of play", _fcrt.isRunning() );
			_fcrt.stop ();
		}
	}
}